package com.multimedia.scala.euler

import scala.collection.mutable.ListBuffer
import com.multimedia.scala.Primes
import scala.annotation.tailrec
import scala.concurrent.MailBox
import scala.actors._
import scala.actors

object Asd108 {
    def main(args : Array[String]) : Unit = {
        /*val simples = Primes.findSimples(100000)
        var n = 1
        while (func1(n)<1000) {
            n+=1
        }
        println(n)
        println(simples.take(n))
        println(simples.take(n).reduce(_*_))*/
        //bruteForce
        //getMultiplyers(100).removeDuplicates.foreach(println)
        println(func1(9, 613))
    }
    
    
    @tailrec
    def func1(n: Int, acc: Int = 2): Int = {
        if (n==1) return acc
        func1(n-1, acc*3-1)
    }

    def getMultiplyers(max: Int, list: List[Int] = List(2, 3, 5, 7, 11, 13, 17)): List[Int] = {
        def recurse(last: Int, acc: ListBuffer[Int]): ListBuffer[Int] = {
            if (acc.last>max) return acc
            if (last==acc.size) return acc
            println(last, acc.last)
            val size = acc.size-1
            for (i <- last to size) {
              list.foreach(x=>{
                  val y = x*acc(i)
                  if (y<max&& !acc.contains(y)) acc+=y
              })
            }
            
            return recurse(size+1, acc)
        }
        return recurse(0, ListBuffer[Int]()++list).toList.removeDuplicates
    }
    
    def bruteForce = {
        val simples = Primes.findSimples(100000)
        val tasks = new MailBox()
        val results = new MailBox()
        val least = 4000000
        val max = 2*3*5*7*11*13*17

        val base = 1
        var last = base
        val multiplyers = getMultiplyers(max).sort((x, y)=>x<y)
        var next = 0
        def nextLast: Int = {
            next += 1
            last * multiplyers(next-1)
        }

        val slaves = (1 to 4).map(x=>new Slave(tasks, results))
        slaves.foreach(x=>{
            x.start()
            tasks send Count(least, nextLast)
        })
        //(4 to 8).foreach(x=>tasks send Count(1, 36))
        var rez = Result(0, Math.MAX_INT)
        while (rez.solutions<least&&last<max) {
        //while (rez.n < 2311) {
            results receive {
              case Result(solutions, n) => {
                  println("n="+n+" s="+solutions+" "+Primes.factor(n, simples))
                  if (solutions>least) {
                      if (n<rez.n) {
                    	  rez = Result(solutions, n)
                      }
                  }
                  if (rez.solutions < least) tasks send Count(least, nextLast)
              }
            }
        }
        println("calculation ended")
        slaves.foreach(x=>tasks send Stop)
        println(rez)
    }
    
    class Slave(tasks: MailBox, results: MailBox) extends Actor {
        @tailrec
        private def findRez(n: BigInt, x: BigInt, acc: Int = 0): Int = {
            if (x > n * 2) return acc
            if ((n*x)%(x-n)==0){
                //println("n="+n+" x="+x+" y="+(n*x)/(x-n)+" s="+acc)
                findRez(n, x+1, acc+1)
            } else findRez(n, x+1, acc)
        }
        def act() {
            loop {
                tasks receive {
                  case Count(least, n) => {
                      val rez = findRez(n, n+1)
                      //println(n->rez)
                      results send Result(rez, n)
                  }
                  case Stop => exit()
                }
            }
        }
    }
 
    case class Count(least: Int, n: Int)
    case class Result(solutions: Int, n: Int)
    case class Stop
    
}
